
#include "qgraphicssystem.h"
#include "windowsurface.h"
#include <QtGui/private/qpixmap_raster_p.h>
#include <QApplication>
#include <QMouseEvent>

QT_BEGIN_NAMESPACE

OGraphicsSystem::OGraphicsSystem()
{
    qDebug() << "SYSTEM: constructor";
    connectToServer();
}

QPixmapData *OGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const
{
    qDebug() << "SYSTEM: create pixmap data";
    return new QRasterPixmapData(type);
}

QWindowSurface *OGraphicsSystem::createWindowSurface(QWidget *widget) const
{
    qDebug() << "SYSTEM: create window surface";
        // send create request to the server
        Q_ASSERT(widget);
        if (widget->windowType() == Qt::Desktop)
            return 0;
        return new WindowSurface(widget, const_cast<OGraphicsSystem*>(this));
}

bool OGraphicsSystem::connectToServer()
{
    qDebug() << "SYSTEM: connect to server";
    m_connection.connectToHost(QHostAddress::LocalHost, 2048);
    if (m_connection.waitForConnected()) {
        QObject::connect(&m_connection, SIGNAL(readyRead()), this, SLOT(eventDispatcher()));
        QObject::connect(&m_connection, SIGNAL(disconnected()), QApplication::instance(), SLOT(quit()));
        qDebug() << "SYSTEM: connected to server";
        return true;
    }
    qDebug() << "SYSTEM: unable to connect to server";
    return false;
}


bool OGraphicsSystem::sendRequest(const Request &request)
{
    qDebug() << "SYSTEM: sending request";
    QDataStream stream(&m_connection);
    stream << (*static_cast<const Message*>(&request));
    return m_connection.isValid();
}

bool OGraphicsSystem::waitForResponse(Response &response)
{
    qDebug() << "SYSTEM: waiting for response";
    if (m_connection.waitForReadyRead(-1)) {
        if (m_message.message == Message::ResponseMessage) {
            qDebug() << "SYSTEM: received response";
            response.type = m_message.type;
            response.id = m_message.id;
            response.rect = m_message.rect;
            // clear internal message
            m_message.message = Message::InvalidMessage;
            return true;
        }
    }
    //handleConnectionError();
    return false;
}

void OGraphicsSystem::eventDispatcher()
{
    qDebug() << "SYSTEM: event dispatcher";
    while (m_connection.bytesAvailable()) {
        QDataStream in(&m_connection);
        in >> m_message;
        switch (m_message.message) {
        case Event::EventMessage: {
            WindowSurface *surface = m_surfaces.value(m_message.id);
            QWidget *window = surface ? surface->window() : 0;

            qDebug() << "SYSTEM: received event" << m_message.type << window;
            switch (m_message.type) {
            case Event::GeometryChangeEvent: {
                    //QApplication::hand
                //QWindowSystemInterface::handleGeometryChange(window, m_message.rect.toRect());
                    window->setGeometry(m_message.rect.toRect());
                break; }
            case Event::MouseMoveEvent:{
                QPoint pos = m_message.rect.topLeft().toPoint();
                qDebug() << "=====> Mouse move event" << pos << window;
                Qt::MouseButtons b = Qt::LeftButton;
                QMouseEvent ev(QEvent::MouseMove, pos, pos+window->pos(), Qt::LeftButton, b, Qt::NoModifier);
                QCoreApplication::sendEvent(window, &ev);
                break;}
            case Event::MousePressEvent: {
                 // ### we don't support multiple buttons or any keyboard modifiers
                // ### and we don't support mouse tracking
                QPoint pos = m_message.rect.topLeft().toPoint();
                qDebug() << "=====> Mouse press event" << pos << window;
                Qt::MouseButtons b = Qt::LeftButton;
                //window->mouseMoveEvent();
                window->move(pos);
                QMouseEvent ev(QEvent::MouseButtonPress, pos, pos+window->pos(), Qt::LeftButton, b, Qt::NoModifier);
                QCoreApplication::sendEvent(window, &ev);
                //QWindowSystemInterface::handleMouseEvent(window, pos, pos+window->pos(), b);
                break; }
            case Event::MouseReleaseEvent: {
                 // ### we don't support multiple buttons or any keyboard modifiers
                QPoint pos = m_message.rect.topLeft().toPoint();
                qDebug() << "======> Mouse release event" << pos << window;
                Qt::MouseButtons b = Qt::NoButton;                
                QMouseEvent ev(QEvent::MouseButtonRelease, pos, pos+window->pos(), Qt::NoButton, b, Qt::NoModifier);
                QCoreApplication::sendEvent(window, &ev);
                break; }
            case Event::KeyPressEvent: {
                QString s;
                if ( m_message.rect.x())
                    s = QChar(int(m_message.rect.x()));
                Qt::KeyboardModifiers mods = static_cast<Qt::KeyboardModifiers>(m_message.rect.y());
                //QWindowSystemInterface::handleKeyEvent(window, QEvent::KeyPress, m_message.value, mods, s);
                break; }
            case Event::KeyReleaseEvent: {
                Qt::KeyboardModifiers mods = static_cast<Qt::KeyboardModifiers>(m_message.rect.y());
                //QWindowSystemInterface::handleKeyEvent(window, QEvent::KeyRelease, m_message.value, mods);
                break; }
            }
            break; }
        case Response::ResponseMessage:
        case Request::RequestMessage:
        default:
            qDebug() << "SYSTEM: received wrong message type" << m_message.type << m_message.id;
            break;
        }
        //if (!m_connection.isValid())
        //    handleConnectionError();
    }
}

QT_END_NAMESPACE
